Port C# SDK generator from nextlove-sdk-generator#301
Merged
Conversation
Replace @seamapi/nextlove-sdk-generator with a Metalsmith + Handlebars pipeline (via @seamapi/smith), mirroring the javascript-http and python codegen architecture. The nextlove C# generator (its AST codegen framework, dataclass serializer, and OpenAPI helpers) is ported verbatim under codegen/lib as TEMPORARY output-parity workarounds, so the generated output stays byte-identical after csharpier. A thin, durable Metalsmith plugin (codegen/lib/csharp.ts) drives the port and emits each generated file through a passthrough layout. - codegen/smith.ts: Metalsmith entry point - codegen/lib/csharp.ts: plugin wrapping the ported generator - codegen/lib/generate-csharp-sdk.ts, codegen.ts, dataclass.ts, schema-modifications.ts, endpoint-rules.ts, types.ts, openapi/*: verbatim TEMPORARY ports (grep TEMPORARY to skip in review) - Keep @seamapi/types pinned at 1.691.0 and change-case at ^4; the generated output is tied to both - Adopt @seamapi/smith eslint/tsconfig config; add eslint.config.ts, tsconfig.json, .prettierignore; wire lint/typecheck/format scripts - Bump Node to 24 (.nvmrc, setup action) and CI test matrix to 22 (@seamapi/smith requires Node >=20.9) The generator does not clean the output directory: the previous generator overwrote without deleting, so the committed output still contains stale files for schemas removed from the pinned types. Cleaning would change the output and is deferred (see TODO in smith.ts). @seamapi/blueprint is installed to satisfy the smith peer dependency but is not wired into the pipeline: the port iterates the raw OpenAPI spec for parity, and blueprint 0.55.0 does not parse the pinned types. Verified: generated output is byte-identical after csharpier 0.29.2; npm run lint, typecheck, and format all pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018oCdmrhyAEX8e9sAFRXZAF
The C# test suite pointed SeamClient at https://<random>.fakeseamconnect.seam.vc, a hosted fake Seam Connect service that was returning 500 on /devices/list and failing every network-dependent test. Remove those tests along with the SeamConnectTest fixture that constructed the networked client, and keep the four pure-deserialization tests, which exercise the generated model, enum, and discriminated-union code with no network dependency. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018oCdmrhyAEX8e9sAFRXZAF
Replace the verbatim port of the nextlove C# AST serializer with the Handlebars-template + context architecture used by the python and javascript-http codegen. Serialization now lives in .hbs templates driven by a durable data model and model builder; TEMPORARY banners are reserved for the raw-OpenAPI parsing helpers only, matching the python migration. - Delete the verbatim AST framework (codegen.ts), the serializer (dataclass.ts), and the main loop (generate-csharp-sdk.ts). - Add durable class-model.ts (data interfaces) and build-model.ts (the traversal that produces the data model, preserving every output quirk: group-name reversal, is_void logic, DataContract naming, member order, inline enums, oneOf/JsonSubtypes unions, DeviceProperties forceNullable, errors/warnings message override, reserved keywords, Object vs object). - Add .hbs templates: model.hbs, api.hbs and partials (model-class, enum-def, data-member, oneof-union, route-methods, tostring); load partials via getHandlebarsPartials; add csParams/csNamedArgs/eq helpers. - Stop vendoring static .cs into codegen: the Client/* runtime, the two static Model helpers, and the .sln are normal committed package source under output/csharp/, not codegen assets (remove templates/fs/** and populate-fs.ts). The generator now emits only schema-derived Api/*.cs and Model/*.cs, mirroring how the python codegen only writes seam/routes/. - Remove dead endpoint-rules.ts. Generated output verified byte-identical after csharpier 0.29.2; npm run lint, typecheck, and format pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018oCdmrhyAEX8e9sAFRXZAF
razor-x
marked this pull request as ready for review
July 21, 2026 23:10
Add greppable TODO comments at each spot in the durable codegen files that consults the raw OpenAPI spec or reproduces a previous-generator quirk for output parity, so `grep -rn TODO codegen/` surfaces every deferred item: - build-model.ts: type resolution (int/float, unions, inline enums), the reserved-keyword remap, the DeviceProperties force-nullable special case, the errors/warnings `message` override heuristic, the discriminated-union quirks (abstract message, reversed KnownSubType order, Unrecognized fallback), and the object-response never-nullable quirk. - csharp.ts: the x-fern-sdk-group-name reversal for class names and the void-endpoint filter. Comments only; generated output stays byte-identical. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018oCdmrhyAEX8e9sAFRXZAF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR ports the C# SDK code generation off
@seamapi/nextlove-sdk-generatoronto the Metalsmith + Handlebars +@seamapi/blueprintarchitecture used byseamapi/javascript-httpand the python SDK (seamapi/python#581), making this repository self-contained. The generated output underoutput/csharp/stays byte-identical after csharpier.Summary
Code generation now lives in
codegen/, built on@seamapi/smith(Metalsmith): a plugin builds a data model from the OpenAPI spec, and logic-free Handlebars templates serialize it to C#.TEMPORARY-bannered files are reserved for the raw-OpenAPI parsing helpers only; all serialization is durable templates + a data model.Key changes
codegen/smith.ts,codegen/lib/csharp.ts): iterates the OpenAPI routes and schemas, builds the model, and emits each file through a Handlebars layout. Only schema-derived files are generated —src/Seam/Api/*.csand the resourcesrc/Seam/Model/*.cs.codegen/lib/class-model.ts(plain interfaces) andcodegen/lib/build-model.ts(the traversal that decides what classes, enums, unions, properties, and routes exist — their names, order, types, and nullability). Preserves every output quirk: thex-fern-sdk-group-namereversal for class names, theis_voidlogic, DataContract naming, member order, inline enums,oneOf/JsonSubtypesdiscriminated unions (top-level and nested),DevicePropertiesforce-nullable, the errors/warningsmessageoverride, reserved-keyword remapping, andObjectvsobject.codegen/layouts/):model.hbs,api.hbs, and partialsmodel-class,enum-def,data-member,oneof-union,route-methods,tostring. Partials are loaded viagetHandlebarsPartials; a few pure helpers (csParams,csNamedArgs,eq) precompute comma-joined lists. csharpier owns indentation, brace style, and line wrapping.codegen/lib/openapi/*,schema-modifications.ts,types.ts): verbatim ports kept as frozen output-parity workarounds, each with a// TEMPORARY:banner and a TODO to delete once generation can be driven by@seamapi/blueprint. These are the onlyTEMPORARYfiles —grep -rn TEMPORARY codegen/lists exactly this set.src/Seam/Client/*, the staticModelhelpers (AsbtractModelSchema.cs,SafeStringEnumConverter.cs), the.sln, README, icon, and test project are normal committed files underoutput/csharp/, not codegen assets — the generator never touches them (mirroring how the python codegen only writesseam/routes/).tsconfig.json/eslint.config.ts/.prettierignoreadopt the@seamapi/smithsetup;generate/lint/typecheck/formatscripts wired; Node bumped to 24 (CI tests on 22, since@seamapi/smithrequires Node ≥20.9).@seamapi/typesstays pinned at1.691.0andchange-caseat^4— the generated output is tied to both.Notes
@seamapi/blueprintis installed to satisfy the smith peer dependency but is not wired into the pipeline: the port iterates the raw OpenAPI spec for output parity, and blueprint0.55.0does not parse the pinned@seamapi/types. TODOs mark the migration path.smith.ts).🤖 Generated with Claude Code
https://claude.ai/code/session_018oCdmrhyAEX8e9sAFRXZAF